﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using WordService.Model;

namespace WordService.Utility
{
    public class ProcessMatrixUtil
    {
        #region 1.过程矩阵：关键字--类别矩阵
        /// <summary>
        /// 1过程矩阵第一个矩阵，关键字和类别的矩阵
        /// </summary>
        /// <returns></returns>
        public static DataTable CalKCMatrix(
            IDictionary<String, IList<Keyword>> sourceKeyword,
            IDictionary<String, KeywordGrid> selectKeyword)
        {
            DataTable resultMatrix = new DataTable();
            // 这里不检测输入了，因为在打开该窗口之前已经检测过了
            // 过滤操作数据源
            IDictionary<String, IList<Keyword>> categoryKeywords = new Dictionary<String, IList<Keyword>>();
            categoryKeywords = GetCategories(sourceKeyword, selectKeyword);
            // 生成矩阵头部
            DataColumn column = new DataColumn("C C\\C R");
            resultMatrix.Columns.Add(column);
            // 类别维度的生成
            IList<String> categories = GetCategories(selectKeyword);
            // 添加第一行的列
            foreach (String key in categories)
            {
                column = new DataColumn(key);
                resultMatrix.Columns.Add(column);
            }
            // 生成每一行的数据，这里需要进行运算
            foreach (String key in categories)
            {
                DataRow row = resultMatrix.NewRow();
                row[0] = key;
                foreach (String innerKey in categories)
                {
                    row[innerKey] = CalKCResult(categoryKeywords[key], categoryKeywords[innerKey], key, innerKey);
                }
                resultMatrix.Rows.Add(row);
            }
            return resultMatrix;
        }

        // 运算某个单元格内容
        private static Int32 CalKCResult(
            IList<Keyword> categoryLeft,
            IList<Keyword> categoryRight,
            String leftCategory,
            String rightCategory)
        {
            Int32 result = Int32.Parse("0");
            if (!leftCategory.Equals(rightCategory))
            {
                // 顶层遍历
                foreach (Keyword left in categoryLeft)
                {
                    // 二层遍历
                    foreach (Keyword right in categoryRight)
                    {
                        if (left.Article.ID == right.Article.ID)
                        {
                            result += Convert.ToInt32((left.Count) + (right.Count));
                        }
                    }
                }
                // 因为矩阵是对称矩阵，所以计算的结果需要除以2，因为每个单元格运算了两次
                result = result / 2;
            }
            else
            {
                // 顶层遍历
                foreach (Keyword left in categoryLeft)
                {
                    // 二层遍历
                    foreach (Keyword right in categoryRight)
                    {
                        if (left.Article.ID == right.Article.ID && right.ID != left.ID)
                        {
                            result += Convert.ToInt32((left.Count) + (right.Count));
                        }
                    }
                }
                // 因为矩阵是对称矩阵，所以计算结果首先要除以2，和前边的结果是一样的，但是因为计算的是对角线
                result = result / 4;
            }
            return result;
        }

        // 根据类别名称以及读取到的内容生成该类别下的关键字Dictionary
        private static IDictionary<String, IList<Keyword>> GetCategories(
            IDictionary<String, IList<Keyword>> sourceKeyword,
            IDictionary<String, KeywordGrid> selectKeyword)
        {
            IDictionary<String, IList<Keyword>> result = new Dictionary<String, IList<Keyword>>();
            // 先添加类别
            foreach (KeywordGrid grid in selectKeyword.Values)
            {
                if (!result.ContainsKey(grid.Category))
                {
                    IList<Keyword> keywordList = new List<Keyword>();
                    sourceKeyword.TryGetValue(grid.Keyword, out keywordList);
                    result.Add(grid.Category, keywordList);
                }
                else
                {
                    IList<Keyword> keywordList = sourceKeyword[grid.Keyword];
                    foreach (Keyword keyword in keywordList)
                    {
                        if (!result[grid.Category].Contains(keyword))
                        {
                            result[grid.Category].Add(keyword);
                        }
                    }
                }
            }
            return result;
        }

        #endregion

        #region 2.过程矩阵：关键字--类别归一化矩阵
        /// <summary>
        /// 1过程矩阵第一个矩阵，关键字和类别归一化矩阵
        /// </summary>
        /// <returns></returns>
        public static DataTable CalKCNormalizeMatrix(
            IDictionary<String, IList<Keyword>> sourceKeyword,
            IDictionary<String, KeywordGrid> selectKeyword)
        {
            DataTable resultMatrix = new DataTable();
            // 生成未归一化举证
            DataTable kcMatrix = CalKCMatrix(sourceKeyword, selectKeyword);
            // 生成矩阵头部
            DataColumn column = new DataColumn("CNC\\CNR");
            resultMatrix.Columns.Add(column);
            // 类别维度的生成
            IList<String> categories = GetCategories(selectKeyword);
            // 添加第一行的列
            foreach (String key in categories)
            {
                column = new DataColumn(key);
                resultMatrix.Columns.Add(column);
            }
            // 生成每一行的数据，这里需要进行运算
            for (int i = 0; i < categories.Count; i++)
            {
                DataRow row = resultMatrix.NewRow();
                row[0] = kcMatrix.Rows[i][0].ToString();
                int index = 0;
                foreach (String innerKey in categories)
                {
                    if (index == i)
                    {
                        row[innerKey] = 1;
                    }
                    else
                    {
                        row[innerKey] = CalKCResult(kcMatrix, i, innerKey);
                    }
                    index++;
                }
                resultMatrix.Rows.Add(row);
            }
            return resultMatrix;
        }

        private static decimal CalKCResult(
            DataTable kcMatrix,
            int row,
            String col)
        {
            Decimal result = 0.0M;
            double currentValue = 0.0;
            // 1.先计算平方和
            int max = kcMatrix.Rows.Count;
            double sumResult = 0.0;
            for (int i = 0; i < max; i++)
            {
                if (i == row)
                {
                    currentValue = Double.Parse(kcMatrix.Rows[row][col].ToString());
                }
                Double cellValue = Double.Parse(kcMatrix.Rows[i][col].ToString());
                sumResult += Math.Pow(cellValue, 2);
            }
            // 2.计算开根号过后结果
            sumResult = Math.Sqrt(sumResult);
            // 3.计算最终结果
            if (sumResult == 0)
            {
                result = 0;
            }
            else
            {
                result = Convert.ToDecimal(currentValue / sumResult);
            }
            return result;
        }
        #endregion

        #region 3.过程矩阵：作者相似度矩阵
        /// <summary>
        /// 作者相似度矩阵
        /// </summary>
        /// <param name="categoryArticleIds"></param>
        /// <param name="authorArticleIds"></param>
        /// <returns></returns>
        private static Int32 CalACResult(IList<Int64> categoryArticleIds, IList<Int64> authorArticleIds)
        {
            Int32 result = 0;
            foreach (Int64 aId in authorArticleIds)
            {
                if (categoryArticleIds.Contains(aId))
                {
                    result++;
                }
            }
            return result;
        }
        /// <summary>
        /// 3过程矩阵第三个矩阵，作者相似度矩阵
        /// </summary>
        /// <returns></returns>
        public static DataTable CalACMatrix(
            IDictionary<String, IList<Keyword>> sourceKeyword,
            IDictionary<String, KeywordGrid> selectKeyword,
            IDictionary<String, IList<Int64>> selectAuthors)
        {
            DataTable resultMatrix = new DataTable();
            // 生成矩阵头部
            DataColumn column = new DataColumn("A C\\A R");
            resultMatrix.Columns.Add(column);
            // 添加第一行的列
            foreach (String key in selectAuthors.Keys)
            {
                column = new DataColumn(key);
                resultMatrix.Columns.Add(column);
            }
            // 生成列别文章列表
            IDictionary<String, IList<Int64>> categoryArticles = GetCategoryArticles(sourceKeyword, selectKeyword);
            foreach (String key in categoryArticles.Keys)
            {
                // 添加第一列
                DataRow row = resultMatrix.NewRow();
                row[0] = key;
                // 从第二列开始遍历
                foreach (String authorName in selectAuthors.Keys)
                {
                    row[authorName] = CalACResult(categoryArticles[key], selectAuthors[authorName]);
                }
                resultMatrix.Rows.Add(row);
            }
            // 生成列矩阵
            return resultMatrix;
        }

        private static IDictionary<String, IList<Int64>> GetCategoryArticles(
            IDictionary<String, IList<Keyword>> sourceKeyword,
            IDictionary<String, KeywordGrid> selectKeyword)
        {
            IDictionary<String, IList<Int64>> resultMap = new Dictionary<String, IList<Int64>>();
            // 类别维度的生成
            IList<String> categories = GetCategories(selectKeyword);
            // 获取关键字的ArticleId列表
            foreach (String key in selectKeyword.Keys)
            {
                IList<Int64> articleIds = new List<Int64>();
                if (sourceKeyword.ContainsKey(key))
                {
                    IList<Keyword> keywords = sourceKeyword[key];
                    foreach (Keyword keyword in keywords)
                    {
                        if (keyword.Article != null && !articleIds.Contains(keyword.Article.ID))
                        {
                            articleIds.Add(keyword.Article.ID);
                        }
                    }
                }
                KeywordGrid currentKeyword = selectKeyword[key];
                if (!resultMap.ContainsKey(currentKeyword.Category))
                {
                    resultMap.Add(currentKeyword.Category, articleIds);
                }
                else
                {
                    IList<Int64> orgIds = resultMap[currentKeyword.Category];
                    foreach (Int64 aId in articleIds)
                    {
                        if (!orgIds.Contains(aId))
                        {
                            orgIds.Add(aId);
                        }
                    }
                }
            }
            return resultMap;
        }
        #endregion

        #region 4.过程矩阵：作者相似度归一矩阵
        /// <summary>
        /// 4过程矩阵第三个矩阵，作者相似度矩阵
        /// </summary>
        /// <returns></returns>
        public static DataTable CalACNormalizeMatrix(
            IDictionary<String, IList<Keyword>> sourceKeyword,
            IDictionary<String, KeywordGrid> selectKeyword,
            IDictionary<String, IList<Int64>> selectAuthors)
        {
            DataTable resultMatrix = new DataTable();
            // 作者相似度的基本矩阵
            DataTable authorMatrix = CalACMatrix(sourceKeyword, selectKeyword, selectAuthors);
            // 获取作者列表
            IList<String> columns = new List<String>();
            IList<String> rows = new List<String>();
            foreach (String author in selectAuthors.Keys)
            {
                columns.Add(author);
                rows.Add(author);
            }
            // 生成矩阵头部
            DataColumn column = new DataColumn("ANC\\ANR");
            resultMatrix.Columns.Add(column);
            // 添加第一行的列
            foreach (String key in columns)
            {
                column = new DataColumn(key);
                resultMatrix.Columns.Add(column);
            }
            // 从第二行开始添加
            for (int j = 0; j < rows.Count; j++)
            {
                DataRow row = resultMatrix.NewRow();
                row[0] = rows[j];
                foreach (String author in columns)
                {
                    if (author.Trim().Equals(rows[j]))
                    {
                        row[author] = 1;
                    }
                    else
                    {
                        row[author] = CalACResult(authorMatrix, rows[j], author);
                    }
                }
                resultMatrix.Rows.Add(row);
            }
            return resultMatrix;
        }

        private static decimal CalACResult(DataTable matrix, String left, String right)
        {
            IList<Int32> leftValues = new List<Int32>();
            IList<Int32> rightValues = new List<Int32>();
            foreach (DataRow row in matrix.Rows)
            {
                leftValues.Add(Int32.Parse(row[left].ToString()));
                rightValues.Add(Int32.Parse(row[right].ToString()));
            }
            double leftSum = 0.0;
            double rightSum = 0.0;
            double sum = 0.0;
            for (int i = 0; i < leftValues.Count; i++)
            {
                sum += leftValues[i] * rightValues[i];
                leftSum += Math.Pow(leftValues[i], 2);
                rightSum += Math.Pow(rightValues[i], 2);
            }
            leftSum = Math.Sqrt(leftSum);
            rightSum = Math.Sqrt(rightSum);
            double result = sum / (leftSum * rightSum);
            return Convert.ToDecimal(result);
        }
        #endregion
        #region 5.过程矩阵：改进作者相似度矩阵
        /// <summary>
        /// 5过程矩阵第五个矩阵，改进作者相似度矩阵
        /// </summary>
        /// <returns></returns>
        public static DataTable CalACUpgradeMatrix(
            IDictionary<String, IList<Keyword>> sourceKeyword,
            IDictionary<String, KeywordGrid> selectKeyword,
            IDictionary<String, IList<Int64>> selectAuthors)
        {
            DataTable resultMatrix = new DataTable();
            // 归一化过后的关键字矩阵
            DataTable keywordMatrix = CalKCNormalizeMatrix(sourceKeyword, selectKeyword);
            // 作者相似度矩阵
            DataTable authorMatrix = CalACMatrix(sourceKeyword, selectKeyword, selectAuthors);
            // 获取类别列表
            IList<String> categories = GetCategories(selectKeyword);
            // 获取作者列表
            IList<String> columns = new List<String>();
            IList<String> rows = new List<String>();
            foreach (String author in selectAuthors.Keys)
            {
                columns.Add(author);
                rows.Add(author);
            }
            // 生成矩阵头部
            DataColumn column = new DataColumn("AUC\\AUR");
            resultMatrix.Columns.Add(column);
            // 添加第一行的列
            foreach (String key in columns)
            {
                column = new DataColumn(key);
                resultMatrix.Columns.Add(column);
            }
            // 从第二行开始添加
            for (int j = 0; j < rows.Count; j++)
            {
                DataRow row = resultMatrix.NewRow();
                row[0] = rows[j];
                foreach (String author in columns)
                {
                    if (author.Trim().Equals(rows[j]))
                    {
                        row[author] = 1;
                    }
                    else
                    {
                        row[author] = CalACUResult(keywordMatrix, authorMatrix, j, rows, author, categories);
                    }
                }
                resultMatrix.Rows.Add(row);
            }
            return resultMatrix;
        }
        private static decimal CalACUResult(DataTable keywordMatrix, DataTable authorMatrix, int fromIndex, IList<String> authors, String toAuthor, IList<String> categories)
        {
            double result = 0.0;
            // From
            String fromAuthor = authors[fromIndex];
            // To: columnName
            IList<Int32> fromValues = new List<Int32>();
            IList<Int32> toValues = new List<Int32>();
            foreach (DataRow row in authorMatrix.Rows)
            {
                fromValues.Add(Int32.Parse(row[fromAuthor].ToString()));
                toValues.Add(Int32.Parse(row[toAuthor].ToString()));
            }
            // 计算分子
            double sum = 0.0;
            for (int fIndex = 0; fIndex < fromValues.Count; fIndex++)
            {
                String fromCategory = categories[fIndex];
                for (int tIndex = 0; tIndex < toValues.Count; tIndex++)
                {
                    double baseValue = 0;
                    String toCategory = categories[tIndex];
                    baseValue = fromValues[fIndex] * toValues[tIndex];
                    double keywordValue = GetKeywordValue(keywordMatrix, fromCategory, toCategory);
                    sum += baseValue * keywordValue;
                }
            }
            // 计算分母
            double fromSum = 0.0;
            double toSum = 0.0;
            for (int i = 0; i < fromValues.Count; i++)
            {
                fromSum += Math.Pow(fromValues[i], 2);
                toSum += Math.Pow(toValues[i], 2);
            }
            fromSum = Math.Sqrt(fromSum);
            toSum = Math.Sqrt(toSum);
            result = sum / (fromSum * toSum);
            return Convert.ToDecimal(result);
        }

        private static decimal CalACFResult(DataTable keywordMatrix, DataTable authorMatrix, int fromIndex, IList<String> authors, String toAuthor, IList<String> categories)
        {
            double result = 0.0;
            // From
            String fromAuthor = authors[fromIndex];
            // To: columnName
            IList<Int32> fromValues = new List<Int32>();
            IList<Int32> toValues = new List<Int32>();
            foreach (DataRow row in authorMatrix.Rows)
            {
                fromValues.Add(Int32.Parse(row[fromAuthor].ToString()));
                toValues.Add(Int32.Parse(row[toAuthor].ToString()));
            }
            // 计算分子
            double sum = 0.0;
            for (int fIndex = 0; fIndex < fromValues.Count; fIndex++)
            {
                String fromCategory = categories[fIndex];
                for (int tIndex = 0; tIndex < toValues.Count; tIndex++)
                {
                    double baseValue = 0;
                    String toCategory = categories[tIndex];
                    baseValue = fromValues[fIndex] * toValues[tIndex];
                    double keywordValue = GetKeywordValue(keywordMatrix, fromCategory, toCategory);
                    sum += baseValue * keywordValue;
                }
            }
            // 计算分母
            double fromSum = 0.0;
            double toSum = 0.0;
            for (int i = 0; i < fromValues.Count; i++)
            {
                double currentFrom = 0.0;
                for (int j = 0; j < categories.Count; j++)
                {
                    if (fromValues[i] == fromValues[j])
                    {
                        currentFrom += fromValues[i] * GetKeywordValue(keywordMatrix, categories[j], categories[i]);
                    }
                    else
                    {
                        currentFrom += (fromValues[j]) * GetKeywordValue(keywordMatrix, categories[j],categories[i]);
                    }
                }
                fromSum += Math.Pow(currentFrom, 2);
                double currentTo = 0.0;
                for (int j = 0; j < categories.Count; j++)
                {
                    if (toValues[i] == toValues[j])
                    {
                        currentTo += toValues[i] * GetKeywordValue(keywordMatrix, categories[j], categories[i]);
                    }
                    else
                    {
                        currentTo += (toValues[j]) * GetKeywordValue(keywordMatrix, categories[j], categories[i]);
                    }
                }
                toSum += Math.Pow(currentTo, 2);
            }
            fromSum = Math.Sqrt(fromSum);
            toSum = Math.Sqrt(toSum);
            result = sum / (fromSum * toSum);
            return Convert.ToDecimal(result);
        }

        private static double GetKeywordValue(DataTable keywordMatrix, String fCategory, String tCategory)
        {
            if (fCategory.Equals(tCategory))
            {
                return 1.0;
            }
            else
            {
                double result = 0;
                for (int i = 0; i < keywordMatrix.Rows.Count; i++)
                {
                    if (keywordMatrix.Rows[i][0].ToString().Equals(fCategory))
                    {
                        result = Double.Parse(keywordMatrix.Rows[i][tCategory].ToString());
                        break;
                    }
                }
                return result;
            }
        }
        #endregion

        #region 6.过程矩阵：改进作者相似度矩阵
        /// <summary>
        /// 6过程矩阵第五个矩阵，改进作者相似度矩阵
        /// </summary>
        /// <returns></returns>
        public static DataTable CalACFinalMatrix(
            IDictionary<String, IList<Keyword>> sourceKeyword,
            IDictionary<String, KeywordGrid> selectKeyword,
            IDictionary<String, IList<Int64>> selectAuthors)
        {
            DataTable resultMatrix = new DataTable();
            // 归一化过后的关键字矩阵
            DataTable keywordMatrix = CalKCNormalizeMatrix(sourceKeyword, selectKeyword);
            // 作者相似度矩阵
            DataTable authorMatrix = CalACMatrix(sourceKeyword, selectKeyword, selectAuthors);
            // 获取类别列表
            IList<String> categories = GetCategories(selectKeyword);
            // 获取作者列表
            IList<String> columns = new List<String>();
            IList<String> rows = new List<String>();
            foreach (String author in selectAuthors.Keys)
            {
                columns.Add(author);
                rows.Add(author);
            }
            // 生成矩阵头部
            DataColumn column = new DataColumn("AUC\\AUR");
            resultMatrix.Columns.Add(column);
            // 添加第一行的列
            foreach (String key in columns)
            {
                column = new DataColumn(key);
                resultMatrix.Columns.Add(column);
            }
            // 从第二行开始添加
            for (int j = 0; j < rows.Count; j++)
            {
                DataRow row = resultMatrix.NewRow();
                row[0] = rows[j];
                foreach (String author in columns)
                {
                    if (author.Trim().Equals(rows[j]))
                    {
                        row[author] = 1;
                    }
                    else
                    {
                        row[author] = CalACFResult(keywordMatrix, authorMatrix, j, rows, author, categories);
                    }
                }
                resultMatrix.Rows.Add(row);
            }
            return resultMatrix;
        }
        #endregion
        #region 公共函数
        private static IList<String> GetCategories(IDictionary<String, KeywordGrid> selectKeyword)
        {
            IList<String> categories = new List<String>();
            foreach (KeywordGrid grid in selectKeyword.Values)
            {
                if (!categories.Contains(grid.Category))
                {
                    categories.Add(grid.Category);
                }
            }
            return categories;
        }
        #endregion

    }
}
